package threadSafe;

import com.google.common.collect.Lists;

import java.util.ArrayList;
import java.util.Hashtable;

/**
 * @author： pang-yun
 * @date： 2021-10-18 11:08
 * 功能目的 ：用于
 *
 * 成员变量 两个线程容易报错 因为共享内存  list 中还未被 add 数据  就remove
 */

public class ThreadUnsafe {
    static final int THREAD_NUMBER =2;
    static final int LOOP_NUMBER =200;

    public static void main(String[] args) {
        SafeDemo safeDemo = new SafeDemo();
        for (int i=0; i<THREAD_NUMBER;i++){
            new Thread(()->{
                safeDemo.method1(LOOP_NUMBER);
            },"Thread"+(i+1)).start();
        }
    }
}

// ArrayList 被 多个线程共享  多个线程调用 method1 会产生错误
class UnSafeDemo{
    ArrayList<String> list = Lists.newArrayList();

    public void method1(int loopNumber) {
        for (int i = 0; i < loopNumber; i++) {
            // 临界区  产生 竟态条件
            method2();
            method3();
        }
    }

    private void method2() {
        list.add("1");
    }

    private void method3() {
        list.remove(0);
    }
}

//局部变量
// Arraylist 的初始化会 在 method1 方法中  每个线程 调用时都会 初始化一个  因此不会 发生安全问题
class SafeDemo{
    public void method1(int loopNumber) {
        // 变成局部变量
        ArrayList<String> list = Lists.newArrayList();
        for (int i = 0; i < loopNumber; i++) {
            // 临界区  产生 竟态条件
            method2(list);
            method3(list);
        }
    }

    private void method2(ArrayList<String> list) {
        list.add("1");
    }

    private void method3(ArrayList<String> list) {
        list.remove(0);
    }

}


// 方法修饰符带来的问题  如果把method2 和 method3 的 方法修改为 public 会不会代理 线程安全问题？
// 不会   调用 method2  method3 也 需要 传入 new的 ArrayList  不会产生 冲突

class SafePublic {
    public void method1(int loopNumber) {
        // 变成局部变量
        ArrayList<String> list = Lists.newArrayList();
        for (int i = 0; i < loopNumber; i++) {
            // 临界区  产生 竟态条件
            method2(list);
            method3(list);
        }
    }

    public void method2(ArrayList<String> list) {
        list.add("1");
    }

    public void method3(ArrayList<String> list) {
        list.remove(0);
    }

    // 在 改为 public后  为其添加子类  覆盖方法 method2 3   会出问题么？
    // 又相当于 多个线程操作一个对象  会发生问题
    class SafePublicSub extends SafePublic{
        @Override
        public void method3(ArrayList<String> list) {
            new Thread(()->{
                list.remove(0);
            }).start();
        }


    }


    //  为 防止子类 重写 这些情况发生  可以将方法改为 private  或者 前面加 final    这里显示了 final  private的 安全 意义    开闭原则中的 闭合
}
